package com.shop.shopserver.filter;
import com.shop.shopserver.handler.CustomAuthenticationFailureHandler;
import com.shop.shopserver.handler.CustomAuthenticationSuccessHandler;
import com.shop.shopcommon.token.PhoneVerificationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.*;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.Assert;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 自定义登录请求过滤器，继承自 AbstractAuthenticationProcessingFilter
 * <p>
 * 登录请求的处理逻辑：
 * 1. 根据不同请求参数，选择不同的认证方式
 * 2. 登录成功后的处理逻辑
 * 3. 登录失败后的处理逻辑
 */
public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private SecurityContextRepository securityContextRepository = new NullSecurityContextRepository();

    private RememberMeServices rememberMeServices = new NullRememberMeServices();

    @Autowired
    private CustomAuthenticationSuccessHandler  customAuthenticationSuccessHandler;
    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    public CustomAuthenticationFilter(String defaultFilterProcessesUrl, AuthenticationManager authManager) {
        super(defaultFilterProcessesUrl);
        setAuthenticationManager(authManager);
    }

    /**
     * 登录请求的处理逻辑 根据不同请求参数，选择不同的认证方式
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String loginType = request.getParameter("loginType");

        if ("username".equals(loginType)) {
            // 登录方式：用户名密码
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } else if ("phone".equals(loginType)) {
            // 登录方式：手机号验证码
            String phone = request.getParameter("phone");
            String verificationCode = request.getParameter("verificationCode");
            // 创建一个手机号验证码的认证令牌
            return getAuthenticationManager().authenticate(new PhoneVerificationToken(phone, verificationCode));
        } else {
            throw new IllegalArgumentException("Invalid login type");
        }
    }

    /**
     * 登录成功后的处理逻辑
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        // 创建了一个空的安全上下文对象，并将其与当前线程绑定
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        SecurityContextHolder.setContext(context);
        this.securityContextRepository.saveContext(context, request, response);

        // 记录日志
        if (this.logger.isDebugEnabled()) {
            this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
        }

        // 记录用户的登录状态以便后续自动登录
        this.rememberMeServices.loginSuccess(request, response, authResult);
        if (this.eventPublisher != null) {
            this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
        }

        // 调用自定义的成功登录处理器，实现返回响应结果
        this.customAuthenticationSuccessHandler.onAuthenticationSuccess(request, response, authResult);

    }

    /**
     * 登录失败后的处理逻辑
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        // 清空 SecurityContextHolder 中的安全上下文信息
        SecurityContextHolder.clearContext();
        // 记录日志
        this.logger.trace("Failed to process authentication request", failed);
        this.logger.trace("Cleared SecurityContextHolder");
        this.logger.trace("Handling authentication failure");
        // 记住我功能相关的失败逻辑
        this.rememberMeServices.loginFail(request, response);

        // 调用自定义的登录失败处理器，实现返回响应结果
        this.customAuthenticationFailureHandler.onAuthenticationFailure(request, response, failed);

    }

    public void setSecurityContextRepository(SecurityContextRepository securityContextRepository) {
        Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
        this.securityContextRepository = securityContextRepository;
    }

    public void setRememberMeServices(RememberMeServices rememberMeServices) {
        Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
        this.rememberMeServices = rememberMeServices;
    }

}
